#pragma once

#include "btBulletDynamicsCommon.h"
#include "BulletCollision/CollisionShapes/btShapeHull.h"
#include "BulletCollision/CollisionShapes/btConvexPointCloudShape.h"
#include "BulletCollision/CollisionShapes/btConvexPolyhedron.h"

#include "boost/multi_array.hpp"

#include "World.h"
#include <fstream>
#include <iostream>
#include <time.h>
#include <set>
#include <ostream>

#include "PointInfo.h"
#include "RasterInfo.h"
#include "PointToRigidBodyHashTable.h"
#include "GraphManager.h"
//#include "MeshBuilder.h"

//#include "Triangle.h"
#include "LinearMath\btConvexHullComputer.h"
#include "Decomposition.h"


typedef boost::multi_array<RasterInfo, 3> Raster3D;
typedef boost::multi_array<float, 2> Graph;


/// Klasa odpowiedzialna za przeprowadzenie analizy sceny i przekazanie informacji do dalszej obrobki sceny.
class Analyzer
{
public:
	/**
	* Konstruktor.
	* @param world Wskaznik na klase swiata.
	* @param minAABB Wektor okreslajacy najblizszy, skrajny, lewy wierzcholek AABB swiata.
	* @param maxAABB Wektor okreslajacy najdalszy, skrajny, prawy wierzcholek AABB swiata.
	* @param stepSize Wielkosc kroku, z jakim bedzie analizowana scena. Okresla rowniez dlugosc krawedzi szescianu sluzacego do przeprowadzenia analizy.
	*/
	Analyzer(World* world, const btVector3& minAABB, const btVector3& maxAABB, btScalar stepSize = 1.0f);

	/// Destruktor.	
	virtual ~Analyzer(void);

	/// Odpowiada za wywolanie calego procesu analizy i dekompozycji sceny.
	void Run();
	
	/// Lista obiektow na scenie.
	btAlignedObjectArray<ConvexHull> ObstacleHulls;
	/// Lista wyznaczonych bryl.
	btAlignedObjectArray<ConvexHull> DecomposedHulls;

	/// Wskaznik do AABB swiata.
	ConvexHull* WorldHull;

private:
	/// Maksymalna waga danego polozenia.
	static const int MAX_WEIGHT = 26;
	
	/// Sprawdza, czy wspolrzedne punktu nie wychodza poza scene.
	void Clamp(PointInfo& p);

	/// Pobiera wszystkie obiekty znajdujace sie w danym punkcie trojwymiarowej siatki
	bool IsNearObstacle(const PointInfo& p, btAlignedObjectArray<int>& obstaclesIndex);

	/// Tworzy trojwymiarowa siatke szescianow
	void Create3DRaster();

	///Redukuje liczbe punktow pozostawiajac tylko wierzcholki.
	void MarkNavPoints();

	/// Inicjuje trowymiarowa mape swiata
	void InitMap(int x, int y, int z);
	
	/// Przeprowadza test kolizji kostki w danym polozeniu.
	bool CheckCollision(std::set<int>& obstacles);
	//bool PointToHigh(btVector3& p);

	/// Na podstawie punktow otaczajacych kazdy obiekt tworzy graf polaczen tych punktow.
	void BuildGraphs();

	/// Wyznacza wage elementu trojwymiarowej tablicy swiata na podstawie sasiedztwa.
	int ComputeNeighborhood(PointInfo& p);

	/// Zwraca czas w sekundach
	inline time_t CalculateTime(time_t dt)
	{
		return dt / CLOCKS_PER_SEC;
	}


	/// Wskaznik na szescian
	btRigidBody* testCube;

	/// Rozmiar trojwymiarowej tablicy
	unsigned int size_x;
	/// Rozmiar trojwymiarowej tablicy
	unsigned int size_y;
	/// Rozmiar trojwymiarowej tablicy
	unsigned int size_z;
	
	/// Wymiary swiata
	unsigned int maxX;
	/// Wymiary swiata
	unsigned int maxY;
	/// Wymiary swiata
	unsigned int maxZ;

	/// Trojwymiarowa tablica
	Raster3D map;
	/// Rozmiar korku analizy sceny
	btScalar stepSize;
	/// Zredukowana lista wierzcholkow
	btAlignedObjectArray<PointInfo> navPoints;

	/// Lista obiektow sceny
	btAlignedObjectArray<const btCollisionObject*> collisionObjects;

	/// Wektor opisujacy AABB sceny
	btVector3 minAABB;
	/// Wektor opisujacy AABB sceny
	btVector3 maxAABB;
	/// Wskaznik na obiekt swiata sceny.
	btCollisionWorld* world;

	/// Tablica asocjacyjna zawierajaca inforcje o punktach z otoczenia danego obiektu.
	PointToRigidBodyHashTable hash;
};
